#!/usr/bin/env python

import sys
import re
import time
from datetime import datetime
import os
import fnmatch

TASKS = 0
ISRS = 1
SEMAS = 2
QUEUES = 3
EVENTS = 4
NOTES = 7
AGENTS = 8

tasksnames = []
isrsnames = []
agentsnames = []
queuesnames = []
eventsnames = []
semasnames = []
notesnames = []

nams = []
evts = []

offset_nsec = 0
first_tstamp = 0
ref_offset = 0
flat = 0

def addtask(evtwords):

   global tasksnames
   global offset_nsec

   if evtwords[3] not in tasksnames:
      tasksnames.append(evtwords[3])
      print('NAM ' + str(TASKS) + ' %d %s' %((TASKS * 1000 + tasksnames.index(evtwords[3])) , evtwords[3]))

   print(evtwords[2] + ' ' + str(TASKS) + ' %d %d' %((TASKS * 1000 + tasksnames.index(evtwords[3])), int(evtwords[0]) - offset_nsec + first_tstamp))
   print('DSC 0 0 %s' % evtwords[4])

def addisr(evtwords):

   global isrsnames
   global offset_nsec

   if evtwords[3] not in isrsnames:
      isrsnames.append(evtwords[3])
      print('NAM ' + str(ISRS) + ' %d %s' %((ISRS * 1000 + isrsnames.index(evtwords[3])) , evtwords[3]))

   print(evtwords[2] + ' ' + str(ISRS) + ' %d %d' %((ISRS * 1000 + isrsnames.index(evtwords[3])), int(evtwords[0]) - offset_nsec + first_tstamp))
   print('DSC 0 0 %s' % evtwords[4])

def addagent(evtwords):

   global agentsnames
   global offset_nsec

   if evtwords[3] not in agentsnames:

      agentsnames.append(evtwords[3])
      print('NAM ' + str(AGENTS) + ' %d %s' %((AGENTS * 1000 + agentsnames.index(evtwords[3])) , evtwords[3]))

   print(evtwords[2] + ' ' + str(AGENTS) + ' %d %d' %((AGENTS * 1000 + agentsnames.index(evtwords[3])), int(evtwords[0]) - offset_nsec + first_tstamp))
   print('DSC 0 0 %s' % evtwords[4])

def addevent(evtwords):

   global eventsnames
   global offset_nsec

   if evtwords[3] not in eventsnames:
      eventsnames.append(evtwords[3])
      print('NAM ' + str(EVENTS) + ' %d %s' %((EVENTS * 1000 + eventsnames.index(evtwords[3])) , evtwords[3]))

   print('OCC ' + str(EVENTS) + ' %d %d' %((EVENTS * 1000 + eventsnames.index(evtwords[3])), int(evtwords[0]) - offset_nsec + first_tstamp))
   print('DSC 0 0 %s' % evtwords[4])

def addsema(evtwords):

   global semasnames
   global offset_nsec

   if evtwords[3] not in semasnames:
      semasnames.append(evtwords[3])
      print('NAM ' + str(SEMAS) + ' %d %s' %((SEMAS * 1000 + semasnames.index(evtwords[3])) , evtwords[3]))

   print('OCC ' + str(SEMAS) + ' %d %d' %((SEMAS * 1000 + semasnames.index(evtwords[3])), int(evtwords[0]) - offset_nsec + first_tstamp))
   print('DSC 0 0 %s' % evtwords[4])

def addnote(evtwords):

   global notesnames
   global offset_nsec

   if evtwords[3] not in notesnames:
      notesnames.append(evtwords[3])
      print('NAM ' + str(NOTES) + ' %d %s' %((NOTES * 1000 + notesnames.index(evtwords[3])), evtwords[3]))

   print('OCC ' + str(NOTES) + ' %d %d' %((NOTES * 1000 + notesnames.index(evtwords[3])), int(evtwords[0]) - offset_nsec + first_tstamp))
   print('DSC 0 0 %s' % evtwords[4])

def addqueue(evtwords):

   global queuesnames
   global offset_nsec

   if evtwords[3] not in queuesnames:
      queuesnames.append(evtwords[3])
      print('NAM ' + str(QUEUES) + ' %d %s' %((QUEUES * 1000 + queuesnames.index(evtwords[3])) , evtwords[3]))

   print(evtwords[2] + ' ' + str(QUEUES) + ' %d %d %s' %((QUEUES * 1000 + queuesnames.index(evtwords[3])), int(evtwords[0]) - offset_nsec + first_tstamp, evtwords[4]))


def roundToNearest(number, multiple):
   half = multiple / 2;
   return number + half - (number + half) % multiple;

def build(tdifilename):

   global nams
   global evts
   global first_tstamp
   global ref_offset

   f = open(tdifilename)

   for line in f:
      if line.startswith('END'):

         #
         # Obtained from tdidump
         # END 0 1301636265522843000 20281195856967 20281196250458 Fri Apr  1 05:37:45 2011
         #
         # Obtained from log2tdi - time stamp with a date
         # END 0 1301636265522843000 20281090149000 20281090149000 Fri Apr  1 05:37:45 2011
         #
         # Obtained from log2tdi - time stamp without a date
         # END 0 0 20281090149000 20281090149000 1970-01-01 00:00:00
         #

         offset = int(line.split()[4])
         #sys.stderr.write('%s, offset is %d\n' % (tdifilename, offset))

         '''
         if ref_offset == 0:
            ref_offset = offset
         else:
            hours = roundToNearest(abs(ref_offset - offset), 3600000000000) / 3600000000000

            if (flat == 0):
               sys.stderr.write('abs is %d, hours is %d, not flattening...\n' % (abs(ref_offset - offset), hours))
               if offset > ref_offset:
                  offset = offset - (3600000000000 * hours)

               else:
                  offset = offset + (3600000000000 * hours)

            else:
               sys.stderr.write('abs is %d, hours is %d, flattening...\n' % (abs(ref_offset - offset), hours))
               offset = ref_offset
         '''

         '''
         if ref_offset == 0:
            ref_offset = offset
            sys.stderr.write('\'%s\' first file, it\'s offset is %d, applying offset %d\n' % (tdifilename, offset, offset))

         else:
            if offset < ref_offset:
               old_offset = offset
               offset-= ref_offset - old_offset
               sys.stderr.write('\'%s\' next file, it\'s offset is %d ( < first offset ), applying offset %d\n' % (tdifilename, old_offset, offset))
            else:
               old_offset = offset
               offset-= old_offset - ref_offset
               sys.stderr.write('\'%s\' next file, it\'s offset is %d ( >= first offset ), applying offset %d\n' % (tdifilename, old_offset, offset))
         '''
         offset = 0


   f.seek(0)
   qvals = []
   qnams = []
   qtstamps = []

   localnams = []

   for line in f:

      #####
      if line.startswith('OCC'):

         occwords = line.split()
         tstamp = int(occwords[3])

         #if first_tstamp == 0:
         #   first_tstamp = tstamp

         dscwords = f.next().split()

         for nam in localnams:
            namwords = nam.split()

            if namwords[0] == tdifilename:
               if occwords[2] == namwords[1]:
                  thenam = namwords[2]

         evts.append(str(offset + tstamp) + ' ' + occwords[1] + ' ' + 'OCC' + ' ' +  thenam + ' ' + dscwords[3])

      #####
      elif line.startswith('STA'):

         stawords = line.split()
         tstamp = int(stawords[3])

         #if first_tstamp == 0:
         #   first_tstamp = tstamp

         if int(stawords[1]) == TASKS or int(stawords[1]) == ISRS or int(stawords[1]) == AGENTS:

            dscwords = f.next().split()

            for nam in localnams:
               namwords = nam.split()

               if namwords[0] == tdifilename:
                  if stawords[2] == namwords[1]:
                     thenam = namwords[2]

            evts.append(str(offset + tstamp) + ' ' + stawords[1] + ' ' + 'STA' + ' ' + thenam + ' ' + dscwords[3])

         elif int(stawords[1]) == QUEUES: # ~ STA / STO

            for nam in localnams:
               namwords = nam.split()
               if namwords[0] == tdifilename:
                  if stawords[2] == namwords[1]:
                     thenam = namwords[2]

            evts.append(str(offset + tstamp) + ' ' + stawords[1] + ' ' + stawords[0] + ' ' + thenam + ' ' + stawords[4])

            qvals[qnams.index(thenam)] += int(stawords[4])
            qtstamps[qnams.index(thenam)] = str(offset + tstamp)


      #####
      elif line.startswith('STO'):

         stowords = line.split()
         tstamp = int(stowords[3])

         #if first_tstamp == 0:
         #   first_tstamp = tstamp

         if int(stowords[1]) == TASKS or int(stowords[1]) == ISRS or int(stowords[1]) == AGENTS: # @T+ STO DSC

            dscwords = f.next().split()

            for nam in localnams:
               namwords = nam.split()
               if namwords[0] == tdifilename:
                  if stowords[2] == namwords[1]:
                     thenam = namwords[2]

            evts.append(str(offset + tstamp) + ' ' + stowords[1] + ' ' + 'STO' + ' ' + thenam + ' ' + dscwords[3])

         elif int(stowords[1]) == QUEUES: # ~ STA / STO

            for nam in localnams:
               namwords = nam.split()
               if namwords[0] == tdifilename:
                  if stowords[2] == namwords[1]:
                     thenam = namwords[2]
            
            evts.append(str(offset + tstamp) + ' ' + stowords[1] + ' ' + stowords[0] + ' ' + thenam + ' ' + stowords[4])

            qvals[qnams.index(thenam)] -= int(stowords[4])
            qtstamps[qnams.index(thenam)] = str(offset + tstamp)

      #####
      elif line.startswith('NAM'):

         namwords = line.split()

         localnams.append(tdifilename + ' ' + namwords[2] + ' ' + namwords[3])

         nams.append(tdifilename + ' ' + namwords[2] + ' ' + namwords[3])

         if int(namwords[1]) == QUEUES:
            if not namwords[3] in qnams:
               qnams.append(namwords[3])
               qvals.append(0)
               qtstamps.append('')


   # set the queues back to 0 for merging
   for q in qnams:
      #sys.stderr.write('%d\n' % q)
      #sys.stderr.write('%d\n' % qvals[qnams.index(q)])
      #sys.stderr.write('%s\n' % qnams[qnams.index(q)])
      #sys.stderr.write('%s\n' % qtstamps[qnams.index(q)])
      evts.append(qtstamps[qnams.index(q)] + ' 3 STO ' + qnams[qnams.index(q)] + ' ' + str(qvals[qnams.index(q)]))
      #print evts[-1]
      #'307521273736370 3 STO [qtbrowser][26409][0]mi.fordblks 11568']

   f.close()

def sortby(x):
    try:
        return int(x.split(' ', 1)[0])
    except ValueError:
        return float('inf')


def natural_sort(l): 
    convert = lambda text: int(text) if text.isdigit() else text.lower() 
    alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 
    return sorted(l, key = alphanum_key)

def main():
   global first_tstamp
   global offset_nsec
   global flat

   if len(sys.argv) >= 2:

      #build filelist
      filelist = []
      for filespec in sys.argv[1:]:

         #sys.stderr.write('file=[%s]\n' % filespec)
         if filespec == '-f':
            flat = 1;
         else:
            for afile in os.listdir('.'):
               if fnmatch.fnmatch(afile, filespec):
                  if afile not in filelist:
                     filelist.append(afile)

      filelist = natural_sort(filelist)

      for tdifilename in filelist:
         build(tdifilename)

      evts.sort(key = sortby)

      print('TIME 1000000000')
      print('SPEED 1000000000')
      print('MEMSPEED 1000000000')

      first_tstamp = 0

      for evt in evts:
         evtwords = evt.split()

         #if offset_nsec == 0:
         #   offset_nsec = int(evtwords[0])

         if int(evtwords[1]) == NOTES:
            addnote(evtwords)

         elif int(evtwords[1]) == ISRS:
            addisr(evtwords)

         elif int(evtwords[1]) == TASKS:
            addtask(evtwords)

         elif int(evtwords[1]) == AGENTS:
            addagent(evtwords)

         elif int(evtwords[1]) == EVENTS:
            addevent(evtwords)

         elif int(evtwords[1]) == SEMAS:
            addsema(evtwords)

         elif int(evtwords[1]) == QUEUES:
            addqueue(evtwords)

      print('END %d %d %d %s' % (offset_nsec, 0, 0, datetime.utcfromtimestamp(offset_nsec / 1000000000).strftime('%Y-%m-%d %H:%M:%S')))

   else:
      print("Usage: %s <-f> tdifile1 tdifile2..." % sys.argv[0])

if __name__ == "__main__":
   main()
